<?php

/**
 * Description of CalEventController
 *
 * @author Poh Nean
 */
Yii::import('application.components.Schedule.*');

class CalEventApiController extends PsController
{
    const MYSQL_DATETIME_FORMAT = 'Y-m-d H:i:s';
	
	public function accessRules()
	{
		return CMap::mergeArray(array(
					array('allow',
						'roles' => array('Calendar.ManageAgency'),
					)), parent::accessRules());
	}

    /**
     * Updates a Cal Event. Handler for REST GET Method
     * Usage: GET api/calEvent
     */
    public function actionList($start = null, $end = null, $limit = null)
    {
        $dstart = microtime(true);
        $events = $this->loadRange($start, $end);

        $data = array();
        if (!empty($events)) {
            $schedule = new Schedule($events);

            $occurrences = $schedule->getOccurrences(new CDateTime($start), new CDateTime($end));

            foreach ($occurrences as $i => $occurrence) {
                if ($limit > 0 && $i >= $limit) {
                    break;
                }

                $data[] = $occurrence;
            }
        }

        // Send response
        $response = array();
        $response["success"] = true;
        $response["start_date"] = $start;
        $response["end_date"] = $end;
        $response["data"] = $data;

        $json = json_encode($response);

        $dend = microtime(true);
//        echo "<p>Total Items: " . count($occurrences) . "</p>";
//        echo "<p>Time Elapsed: " . ($dend - $dstart) . "</p>";
//        echo "<p>Time Per Item: " . ($dend - $dstart) / count($occurrences) . "</p>";
//        echo "<p>Peak Memory: " . memory_get_peak_usage(true) / 1024 . "Kb</p>";

        print $json;
    }

    /**
     * View a Cal Event.
     * Usage: GET api/calEvent/<id>
     */
    public function actionView()
    {
        throw new CHttpException('404', 'Not Implemented.');
    }

    /**
     * Creates a Cal Event.
     * Usage: POST api/calEvent
     */
    public function actionCreate()
    {
        $response = array();

        $post_vars = $this->getRequestVariables();
        $data = (array) $post_vars->data;

        $calEvent = new CalEvent;
        $calEvent->setAttributes($data);
        $calEvent->ical_type = 'VEVENT';
        $calendar = CalCalendar::model()->ofCurrentAgency()->findByPk($data['calendar_id']);


        $tx = Yii::app()->db->beginTransaction();
        try {
            if ($calendar != null) {
                $calEvent->calendar_id = $calendar->id;
				$calEvent->user_id = $calendar->user_id;
            }

            $valid = $calEvent->validate(array('start_date'));

            if ($valid) {
                $success = $calEvent->save(false);

                if ($data['contact_id']) {
                    $success = $calEvent->associateContact($data['contact_id']) && $success;
                }

                $tx->commit();
            } else {
                $response['success'] = false;
            }
        } catch (CDbException $e) {
            $response['success'] = false;
            $tx->rollback();
        }

        $response['success'] = $success;
        if ($success) {
			$calEvent->refresh();
			
            $response["message"] = "New Event record created.";
            $response["data"] = $calEvent->attributes;
            $response["data"]['contact_id'] = $data['contact_id'];
        } else {
            $response["message"] = "Error creating new event.";
            $response["error"] = $calEvent->getErrors();
        }


        print CJSON::encode($response);
    }

    /**
     * Updates a Cal Event.
     * Usage: PUT api/calEvent/<id>
     */
    public function actionUpdate($id)
    {
        $post_vars = $this->getRequestVariables();
        $data = (array) $post_vars->data;

        if (strrpos($id, "_") != false) {
            list($id, $occurrenceStartTime) = explode("_", $id);
            $occurrenceStartTime = (int) $occurrenceStartTime;
        }

        $calEvent = $this->loadModel($id);

        // update record
        $response = array();

        if ($calEvent != null && !empty($data)) {
            if (!empty($occurrenceStartTime) && !empty($data["start_date"])) {
                $occurrenceStart = new CDateTime($occurrenceStartTime);
                $newOccurrenceStart = new CDateTime($data["start_date"]);
                $newOccurrenceEnd = new CDateTime($data["end_date"]);

                $startShift = $newOccurrenceStart->getTimestamp() - $occurrenceStartTime;
                $newTimespan = $newOccurrenceEnd->getTimestamp() - $newOccurrenceStart->getTimestamp();

                $newStartDate = new CDateTime(strtotime($calEvent->start_date) + $startShift);
                $newEndDate = new CDateTime($newStartDate->getTimestamp() + $newTimespan);

                $diffDays = CDateTime::diffDays($occurrenceStart, $newOccurrenceStart);

                $calEvent->setAttributes($data);

                $calEvent->start_date = $newStartDate;
                $calEvent->end_date = $newEndDate;

                $calEvent->shift($diffDays);
            } else {
                $calEvent->setAttributes($data);
            }

            $valid = $calEvent->validate(array('start_date'));


            if ($calEvent->save(false)) {
                $response["success"] = true;
                
                if ($data['contact_id']) {
                    $calEvent->unassociateAllContacts();
                    $calEvent->associateContact($data['contact_id']);
                }
				
				$calEvent->refresh();

                $response["message"] = "Event record updated.";
                $response["data"] = $calEvent->attributes;
                $response["data"]['contact_id'] = $data['contact_id'];
            } else {
                $response["success"] = false;
                $response["message"] = "Error updating event.";
                $response["error"] = $calEvent->getErrors();
            }
        } else {
            $response["success"] = false;
            $response["message"] = "Event does not exist.";
        }

        print CJSON::encode($response);
    }

    /**
     * Delete a Cal Event.
     * Usage: DELETE api/calEvent/<id>
     */
    public function actionDelete($id)
    {
        $response = array();
        $calEvent = $this->loadModel($id);

        if ($calEvent->delete()) {
            $response["success"] = true;
            $response["message"] = "Event Record deleted.";
        } else {
            $response["success"] = false;
            $response["message"] = "Error deleting event.";
        }

        print CJSON::encode($response);
    }

    public function getRequestVariables()
    {
        return json_decode(file_get_contents("php://input"));
    }

    /**
     * Loads a CalEvent Model of the current agent.
     * @param type $id
     * @return type 
     */
    public function loadModel($id)
    {
        return CalEvent::model()->ofCurrentAgency()->findByPk($id);
    }

    /**
     * Load all Calendar events of the current agent until specified end date.
     * Start date is not used because we need to fetch recurring events in the past.
     * @param type $start
     * @param type $end
     * @return type 
     */
    public function loadRange($start = null, $end = null)
    {
        $range_start = new DateTime($start);
        $range_start = $range_start->format(self::MYSQL_DATETIME_FORMAT);

        // add a day to the range end to include event times on that day
        $range_end = new DateTime($end);
        $range_end->modify('+1 day');
        $range_end = $range_end->format(self::MYSQL_DATETIME_FORMAT);

        // Query conditions
        $conditions = array();
        $conditions["pastRecurring"] = "(start_date < :range_start AND rrule IS NOT NULL)";
        $conditions["startsInRange"] = "(start_date >= :range_start AND start_date <= :range_end)";
        $conditions["endsInRange"] = "(end_date >= :range_start AND end_date <= :range_end)";
        $conditions["spansRange"] = "(start_date < :range_start AND end_date > :range_end)";

        // Fetch data from database
        $criteria = new CDbCriteria();
        $criteria->condition = implode(" OR ", $conditions);
        $criteria->params = array(
            ':range_start' => $range_start,
            ':range_end' => $range_end,
        );

        return CalEvent::model()->ofCurrentAgency()->findAll($criteria);
    }

}

?>
